#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define Tamano 8
/*
*
* 66.20 Organizaci�n de Computadoras
*
* 1er. Cuatrimestre 2013
* 
* Profesores: Leandro Santi - Hernan Perez Masci
* Alumnos: Roitman - Rodriguez Vazquez - Castiglioni Dupin
*
*/
void error (char *message){
	fputs(message, stderr);
	getchar();
	exit(1);
}

void errorInform (char* message){
	fputs(message, stderr);
	exit(1);
}

void imprimirAyuda() {
	printf("Usage:\n");  
	printf("   tp0 -h\n");
	printf("   tp0 -V\n");
	printf("   tp0 [options]\n");
	printf("Options:\n");
	printf("  -h, --help      Print this information.\n");
	printf("  -V, --version   Print version and quit.\n");
	printf("  -b, --binary    Generate a output file consisting of '1's and '0's.\n");
	printf("  -r, --reverse   Generate a output file using an encoded file as input (default mode).\n");
	printf("  -i, --input     Path to input file (defaults to stdin).\n");
	printf("  -o, --output    Path to output file (defaults to stdout).\n");
	printf("\n");
	printf("Examples:\n");
	printf("tp0 -i -\n");
	printf("tp0 -r -i - -o -\n");
	printf("tp0 -b -i /dev/*urandom -o /tmp/random-1s-and-0s\n");
}

void codificarABinario(int numero,unsigned char* binario) {
	int k = 0;
	int n = 0;
	int p =0;
	int decAlmacenado  = 0;
    int  residuo;     /* valor residual que se va obteniendo al dividir por 2 */
    unsigned char temporal[Tamano];
	
	/* inicializo el vector  en ceros */
	while ( p < Tamano){
	  temporal[p] = '0';
	  p++;
	}

	/*copiamos el valor de decimal a la variable decAlmacenado*/
	do{
	    decAlmacenado  = numero;       /* Se toma el valor del residuo */
		residuo    = numero % 2;       /* Reducimos el numero a la mitad en "Divisiones consecutivas" */
		numero   = numero / 2;
		temporal[k++] = residuo + '0';
	} while (numero > 0);

	/* Se invierte la cadena para poner el binario en orden*/
	k=8;
	while (k >= 0) {
		binario[n++] = temporal[--k];
	}
	binario[n-1] = 0;
	
}

int decodificarADecimal( unsigned char* binario)
{
	 int i;
	 int potencia = 1;    /* La variable potencia lleva el valor de la  potencia de 2 por la cual se va a multiplicar el digito almacenado dependiendo de su posicion*/
	 int decimal = 0;     /* El equivalente decimal de la cadena binaria se inicia a 0 */

	 // Este ciclo for evalua cada una de las  entradas del arreglo que fueron introducidas  por el usuario, las multiplica por la potencia de 2 correspondiente a su posicion y los
	 // productos los va sumando. La suma total sera  el valor decimal del numero.

	 for ( i = Tamano-1; i >= 0; i-- )
	 {
		 switch( binario[i] )
		 {
			 case '0':
				 decimal += 0 * potencia;
				 potencia *= 2;
			 	 break;
			 case '1':
				 decimal += 1 * potencia;
				 potencia *= 2;
			 	 break;
			 default:
				 break;
		 }
	 }

	 return decimal;
}

int main(int argc, char *argv[]) {
	
	FILE *inputfile;
	FILE *outputfile;
	
	int action = 1;  // action = 0  -----binary
					 // action = 1	-----reverse (default)
	
	char *input = NULL;
	char *output = NULL;
	
	char caracter;
	
	int g = 0;
	int decimal;
	unsigned char byteSalida[Tamano];
	unsigned char byteEntrada[Tamano];
		
	int i;
	int x;
	const char *version = "1.0";
	int contador = 0;

	inputfile = stdin;
	outputfile = stdout;

	for (i = 1; i < argc; i++) {
		if ((strcmp(argv[i], "-h")==0) || (strcmp(argv[i], "--help")==0))    x=1;
		if ((strcmp(argv[i], "-V")==0) || (strcmp(argv[i], "--version")==0)) x=2;
		if ((strcmp(argv[i], "-i")==0) || (strcmp(argv[i], "--input")==0))   x=3;
		if ((strcmp(argv[i], "-o")==0) || (strcmp(argv[i], "--output")==0))  x=4;
		if ((strcmp(argv[i], "-b")==0) || (strcmp(argv[i], "--binary")==0))  x=5;
		if ((strcmp(argv[i], "-r")==0) || (strcmp(argv[i], "--reverse")==0)) x=6;
		
		switch(x) {
			case 1: {   //-h
				imprimirAyuda();
				exit(1);
				break;
			}
			case 2: {   //-V
				printf("\nVersion: %s\n",version);
				exit(1);
				break; 
			}
			case 3: {   // -i inputfile
				i++;
				if (argv[i] != NULL)  {
					if (argv[i][0] == '-') {
						i--;
					} else {
						input = argv[i];
					}
				}
				break;
			}
			case 4: {   // -o outputfile
				i++;
				if (argv[i] != NULL)  {
					if (argv[i][0] == '-') {
						i--;
					}else{
						output = argv[i];
					}
				}
				break;
			}
			case 5: { // -b binary 
				action = 0;
				break;
			}
			case 6: { // -r reverse 
				action = 1;
				break;
			}
			default: {
				error ("Syntax error. Use help (tp0 -h or  tp0 --help).\n");
				break;
			}
		} //end switch
	} // end for
	
	if (input != NULL) { 
		if (!(inputfile = fopen(input,"rb"))) {
			error ("Error opening input file.\n");
		}
	}

	if (output != NULL) {
		if (!(outputfile = fopen(output, "wb"))) {
			error ("Error opening output file,\n");
		}
	}

	if (action == 0) {
		//llamar al codificador
		while (g != EOF) {
		      g = fgetc(inputfile);	
                       if (g != EOF) {
				contador++;
				codificarABinario(g,byteSalida);
				if(fprintf(outputfile,"%s",byteSalida) == EOF){
					error ("Error writing output file,\n");
				}
				fprintf(outputfile,"%c",' ');
			}
		}
		if (contador == 0)
		 error ("Input file empty,\n");
	} else {
		//comienzo de decodificador
		i = 0;
		while (caracter != EOF) {
			caracter = fgetc(inputfile);
			if (caracter == '1' || caracter == '0' || caracter !='\n')
			{
   			   if (caracter != EOF && i < Tamano) {
				  byteEntrada[i] = caracter;
				  contador++;
				  i++;
			   }else {
					if(i == 8) {
							decimal = decodificarADecimal(byteEntrada);
							if ((fprintf(outputfile,"%c",decimal))== EOF) {
								error ("Error writing outputfile,\n");
							}
							if (caracter == ' ')	
								caracter = fgetc(inputfile);
							i=0;
							byteEntrada[i] = caracter;
							i++;
					}
			  }
			}else{
				if ((caracter != ' ') &&(caracter !='\n') && (caracter !=EOF)){
				errorInform("Invalid character, \n");
				}
			}
		}
		if (contador == 0)
			error ("Input file for decoding empty,\n");
	}
	
	fclose(inputfile);
	fclose(outputfile);

	return 0;
}

